
"""
http binding interface
"""


from market.chat.interface import Interface

from market.chat.declarations import implements
from market.chat import domish


import hashlib, time
#import error
#from session import make_session
#import punjab
#from punjab.xmpp import ns


NS_BIND = 'http://jabber.org/protocol/httpbind'
NS_FEATURES = 'http://etherx.jabber.org/streams'

class DummyElement:
    """dummy element for a quicker parse"""
    # currently not used
    def __init__(self, *args, **kwargs):

        self.children = []



class HttpbElementStream(domish.ExpatElementStream):
    """add rawXml to the elements"""

    def __init__(self, prefixes=None):
        domish.ExpatElementStream.__init__(self)
        self.prefixes = {}
        if prefixes:
            self.prefixes.update(prefixes)
        self.prefixes.update(domish.G_PREFIXES)
        self.prefixStack = [domish.G_PREFIXES.values()]
        self.prefixCounter = 0


    def getPrefix(self, uri):
        if not self.prefixes.has_key(uri):
            self.prefixes[uri] = "xn%d" % (self.prefixCounter)
            self.prefixCounter = self.prefixCounter + 1
        return self.prefixes[uri]

    def prefixInScope(self, prefix):
        stack = self.prefixStack
        for i in range(-1, (len(self.prefixStack)+1) * -1, -1):
            if prefix in stack[i]:
                return True
        return False

    def _onStartElement(self, name, attrs):
        # Generate a qname tuple from the provided name
        attr_str = ''
        defaultUri = None
        uri = None
        qname = name.split(" ")
        if len(qname) == 1:
            qname = ('', name)
            currentUri = None
        else:
            currentUri = qname[0]
        if self.currElem:
            defaultUri = self.currElem.defaultUri
            uri = self.currElem.uri

        if not defaultUri and currentUri in self.defaultNsStack:
            defaultUri = self.defaultNsStack[1]

        if defaultUri and currentUri != defaultUri:

            raw_xml = u"""<%s xmlns='%s'%s""" % (qname[1], qname[0], '%s')

        else:
            raw_xml = u"""<%s%s""" % (qname[1], '%s')


        # Process attributes

        for k, v in attrs.items():
            if k.find(" ") != -1:
                aqname = k.split(" ")
                attrs[(aqname[0], aqname[1])] = v

                attr_prefix = self.getPrefix(aqname[0])
                if not self.prefixInScope(attr_prefix):
                    attr_str = attr_str + " xmlns:%s='%s'" % (attr_prefix,
                                                              aqname[0])
                    self.prefixStack[-1].append(attr_prefix)
                attr_str = attr_str + " %s:%s='%s'" % (attr_prefix,
                                                       aqname[1],
                                                       domish.escapeToXml(v,
                                                                          True))
                del attrs[k]
            else:
                v = domish.escapeToXml(v, True)
                attr_str = attr_str + " " + k + "='" + v + "'"

        raw_xml = raw_xml % (attr_str,)

        # Construct the new element
        e = domish.Element(qname, self.defaultNsStack[-1], attrs, self.localPrefixes)
        self.localPrefixes = {}

        # Document already started
        if self.documentStarted == 1:
            if self.currElem != None:
                if len(self.currElem.children)==0 or isinstance(self.currElem.children[-1], domish.Element):
                    if self.currRawElem[-1] != ">":
                        self.currRawElem = self.currRawElem +">"

                self.currElem.children.append(e)
                e.parent = self.currElem

            self.currRawElem = self.currRawElem + raw_xml
            self.currElem = e
        # New document
        else:
            self.currRawElem = u''
            self.documentStarted = 1
            self.DocumentStartEvent(e)

    def _onEndElement(self, _):
        # Check for null current elem; end of doc
        if self.currElem is None:
            self.DocumentEndEvent()

        # Check for parent that is None; that's
        # the top of the stack
        elif self.currElem.parent is None:
            if len(self.currElem.children)>0:
                self.currRawElem = self.currRawElem + "</"+ self.currElem.name+">"
            else:
                self.currRawElem = self.currRawElem + "/>"
            self.ElementEvent(self.currElem, self.currRawElem)
            self.currElem = None
            self.currRawElem = u''
        # Anything else is just some element in the current
        # packet wrapping up
        else:
            if len(self.currElem.children)==0:
                self.currRawElem = self.currRawElem + "/>"
            else:
                self.currRawElem = self.currRawElem + "</"+ self.currElem.name+">"
            self.currElem = self.currElem.parent

    def _onCdata(self, data):
        if self.currElem != None:
            if len(self.currElem.children)==0:
                self.currRawElem = self.currRawElem + ">" + domish.escapeToXml(data)
                #self.currRawElem = self.currRawElem + ">" + data
            else:
                self.currRawElem = self.currRawElem + domish.escapeToXml(data)
                #self.currRawElem = self.currRawElem + data

            self.currElem.addContent(data)

    def _onStartNamespace(self, prefix, uri):
        # If this is the default namespace, put
        # it on the stack
        if prefix is None:
            self.defaultNsStack.append(uri)
        else:
            self.localPrefixes[prefix] = uri

    def _onEndNamespace(self, prefix):
        # Remove last element on the stack
        if prefix is None:
            self.defaultNsStack.pop()

def elementStream():
    """ Preferred method to construct an ElementStream
    Uses Expat-based stream if available, and falls back to Sux if necessary.
    """
    try:
        es = HttpbElementStream()
        return es
    except ImportError:
        if domish.SuxElementStream is None:
            raise Exception("No parsers available :(")
        es = domish.SuxElementStream()
        return es

# make httpb body class, similar to xmlrpclib
#
class HttpbParse:
    """An xml parser for parsing the body elements."""
    def __init__(self, use_t=False):
        """Call reset to initialize object"""
        self.use_t = use_t # use domish element stream
        self._reset()


    def parse(self, buf):
        """Parse incoming xml and return the body and its children in a list"""
        self.stream.parse(buf)

        # return the doc element and its children in a list
        return self.body, self.xmpp_elements

    def serialize(self, obj):
        """Turn object into a string type"""
        if isinstance(obj, domish.Element):
            obj = obj.toXml()
        return obj

    def onDocumentStart(self, rootelem):
        """The body document has started.
        This should be a body.
        """
        if rootelem.name == 'body':
            self.body = rootelem

    def onElement(self, element, raw_element = None):
        """A child element has been found."""
        if isinstance(element, domish.Element):
            if raw_element:
                self.xmpp_elements.append(raw_element)
            else:
                self.xmpp_elements.append(element)
        else:
            pass

    def _reset(self):
        """Setup the parser"""
        if not self.use_t:
            self.stream = elementStream()
        else:
            self.stream = domish.elementStream()

        self.stream.DocumentStartEvent = self.onDocumentStart
        self.stream.ElementEvent = self.onElement
        self.stream.DocumentEndEvent = self.onDocumentEnd
        self.body = ""
        self.xmpp_elements = []


    def onDocumentEnd(self):
        """Body End"""
        pass

